home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’96
/
O Boy
/
Source
/
AEObj_pd.cp
next >
Wrap
Text File
|
1996-06-21
|
14KB
|
484 lines
/*
AEObj_pd.cp
© Bob Boylan 1996
Revision History
MacHack 1996 initial creation
*/
#include "debug.h"
#include "AEObj_pd.h"
#include "ComputerAEObj_pd.h"
#include "ComputerAETE_da.h"
#include "AppAEObj_pd.h"
#include "Helpers_ut.h"
#include "AEBuild.h"
#include "ProgressProc_hi.h"
#include "FinderAppAEObj_pd.h"
#include <algo.h>
#include <sstream>
// class statics
Int_32 AEObj_pd::_TimeoutinTicks = (3L * 60L);
// -----------------------------------------------------------------
// ctor
//
AEObj_pd::AEObj_pd()
{
}
// -----------------------------------------------------------------
// ctor
//
AEObj_pd::AEObj_pd(AEObj_pd * inParent, DescType inKind, Int_32 inIndex )
{
// get info from the parent object
_AETE = inParent->_AETE;
_AppSignature = inParent->_AppSignature;
_ObjectSpec = inParent->_ObjectSpec;
// place our object type on top of the object spec stack
ObjectSpec_da theObjSpec;
theObjSpec._Kind = inKind;
theObjSpec._Pos = inIndex;
PushObjSpec( theObjSpec );
// update the formal name of this object
{
ostringstream theStream( ios::in | ios::out );
theStream << GetKindName() << " " << inIndex;
_ObjectSpec.back()._FormalName = theStream.str();
}
}
// -----------------------------------------------------------------
// ctor ... from child
//
AEObj_pd::AEObj_pd( AEObj_pd * inChild )
{
// grab the child info for ourselves
_ObjectSpec = inChild->_ObjectSpec;
_ObjectSpec.pop_back();
_AETE = inChild->_AETE;
_AppSignature = inChild->_AppSignature;
}
// -----------------------------------------------------------------
// dtor
//
AEObj_pd::~AEObj_pd()
{
}
// -----------------------------------------------------------------
// Update ... this is where we manage the data coming from the app
//
void
AEObj_pd::Update( ProgressProc_hi &inProgressProc, Int_32 inMaxSubModels )
{
// inform the user as to what is happening
inProgressProc.BeginUpdate();
// first the property values
UpdatePropertyValues( inProgressProc );
// and (if not cancelled) then we do the sub models
if( inProgressProc.UserCancelled() == false )
UpdateSubModelList( inProgressProc, inMaxSubModels );
// finally, tell the user we are all done
inProgressProc.EndUpdate();
}
// -----------------------------------------------------------------
// UpdateSubModelList
//
void
AEObj_pd::UpdateSubModelList( ProgressProc_hi &inProgressProc, Int_32 inMaxSubModels)
{
// grab the list of sub models from the aete
vector<Elem_da> theSubModelTypes = (*_AETE).GetElements( GetKindID() );
// and cycle thru each model type we can hold
vector<Elem_da>::iterator theIter = theSubModelTypes.begin();
vector<Elem_da>::iterator theLast = theSubModelTypes.end();
Int_32 theNModels;
while( (theIter != theLast) && (inProgressProc.UserCancelled() == false) )
{
// how many submodels of this kind do we have?
theNModels = GetSubModelCount( (*theIter)._ID );
Int_32 theMin = 1; // fudge for the application types - the finder doesn't consider itself a process
if( GetKindID() == cComputer ) theMin = 0;
for( Int_32 theIndex = theMin ; theIndex <= min(inMaxSubModels, theNModels ) ; theIndex++ ) // max out at 10 for list limit reason
{
AEObj_pd *theNewObj;
// see if we are creating a regular object ... or an application object
// ... it is awkard due to the fact that the hierarchy isn't carried throughout the os
if( GetKindID() == cComputer )
{
if( theIndex != 0 ) // yet another special case (I hate what that happens)
{
theNewObj = new AppAEObj_pd( this, (*theIter)._ID, theIndex );
}
else
{
theNewObj = new FinderAppAEObj_pd( this, cFinderProcess, 0 );
}
Clone_ut<AEObj_pd> theClone( theNewObj ); // bind with a ref counter
// inform the user
inProgressProc.NewSubModel( theClone );
}
else
{
// the easy case ... a real object hierarchy
theNewObj = new AEObj_pd( this, (*theIter)._ID, theIndex );
Clone_ut<AEObj_pd> theClone( theNewObj ); //bind
// inform the user
inProgressProc.NewSubModel( theClone );
}
}
++theIter; // on to the next object kind
}
}
// -----------------------------------------------------------------
// GetPropertyValue
//
Clone_ut<PropertyValue_pd>
AEObj_pd::GetPropertyValue( Prop_da &inProp )
{
// create the aegizmo string that represents the property we want
ostringstream theStream( ios::in | ios::out );
theStream << "'----':obj {form:prop," <<
"want:type(prop)," <<
"seld:type('" << As4CharString( inProp._ID ) << "')," <<
"from:" << GetObjAddr() << "}";
OSErr theErr;
StAEDescriptor theAppleEvent;
// use gizmos to create the apple event
theErr = AEBuildAppleEvent( kAECoreSuite, kAEGetData,
GetAppAddrType(),
GetAppAddr(),
GetSizeofAppAddr(),
kAutoGenerateReturnID, kAnyTransactionID,
&theAppleEvent.mDesc, theStream.str().c_str() );
dassert( theErr == noErr );
StAEDescriptor theReplyAppleEvent;
// and off with it
theErr = AESend( &theAppleEvent.mDesc, &theReplyAppleEvent.mDesc, kAEWaitReply,
kAENormalPriority, _TimeoutinTicks, nil, nil );
// now see what the app gave us
StAEDescriptor *theResult = new StAEDescriptor;
Clone_ut<StAEDescriptor> theVal( theResult );
if( theErr == noErr )
{
theErr = AEGetParamDesc( theReplyAppleEvent, keyDirectObject, typeWildCard, &theResult->mDesc );
}
// package the return value
PropertyValue_pd *thePVal = new PropertyValue_pd( inProp._ID, theVal, inProp._Name);
Clone_ut<PropertyValue_pd> theRetVal( thePVal );
return theRetVal;
}
// -----------------------------------------------------------------
// GetName
//
string
AEObj_pd::GetName()
{
// quick exit check ... is this a bozo aete?
if( IsValidAETE() == false ) return string("xxx");
// our name starts with the formal name (e.g. Document # 1)
ostringstream theStream( ios::in | ios::out );
theStream << GetKindName() << " # " << _ObjectSpec.back()._Pos ;
// next check and see if we have a name property
vector<Prop_da> theProps = (*_AETE).GetProperties( _ObjectSpec.back()._Kind );
Prop_da thePropWeWant;
thePropWeWant._ID = pName;
vector<Prop_da>::iterator theFoundItem = find( theProps.begin(), theProps.end(), thePropWeWant );
// ok, we found it ... ask the app what it is
if( theFoundItem != theProps.end() )
{
Clone_ut<PropertyValue_pd> theNamePropertyValue = GetPropertyValue( Prop_da(pName) );
_ObjectSpec.back()._Name = Asstring( *theNamePropertyValue );
theStream << string(" (") << _ObjectSpec.back()._Name << string(")");
}
// and package up the return value
return theStream.str();
}
// -----------------------------------------------------------------
// GetKindName ... return the class name of this object
//
string
AEObj_pd::GetKindName()
{
return (*_AETE).GetClassName( _ObjectSpec.back()._Kind );
}
// -----------------------------------------------------------------
// GetKindID ... return the class id of this object
//
DescType
AEObj_pd::GetKindID()
{
return _ObjectSpec.back()._Kind;
}
// -----------------------------------------------------------------
// GetPosition
//
Int_32
AEObj_pd::GetPosition()
{
return _ObjectSpec.back()._Pos;
}
// -----------------------------------------------------------------
// GetParent ... when your walking up the hierarchy
//
Clone_ut< AEObj_pd >
AEObj_pd::GetParent()
{
Clone_ut<AEObj_pd> theRetVal;
dassert( _ObjectSpec.size() > 2 ); // check legality
AEObj_pd *theObj = nil;
// see if our parent should be an application
if( _ObjectSpec[_ObjectSpec.size()-2]._Kind == cFinderProcess )
{
theObj = new AppAEObj_pd( this );
}
else
{ // ahhh ... the easy case
theObj = new AEObj_pd( this );
}
dassert( theObj != nil ); // just checking
// package up the return value
theRetVal = Clone_ut<AEObj_pd>( theObj );
return theRetVal;
}
// -----------------------------------------------------------------
// GetSibling .. great for getting the object to your left or right
//
Clone_ut< AEObj_pd >
AEObj_pd::GetSibling( Int_32 inPositionDelta )
{
// first get the parent that we share
Clone_ut< AEObj_pd > theParent;
theParent = GetParent();
AEObj_pd * theSibling;
// now see what kind of children that parent can have (remember, no one has ugly children!)
if( (*theParent).GetKindID() == cComputer )
{
if( (GetPosition() + inPositionDelta ) != 0 ) // special case for the finder/apps
{
theSibling = new AppAEObj_pd( &(*theParent), cFinderProcess, GetPosition() + inPositionDelta );
}
else
{
theSibling = new FinderAppAEObj_pd( &(*theParent), cFinderProcess, 0 );
}
}
else
{ // the easy case
theSibling = new AEObj_pd( &(*theParent), GetKindID(), GetPosition() + inPositionDelta );
}
theSibling->GetName(); // update name for object label
// package up the return value
Clone_ut< AEObj_pd > theSiblingReturnValue( theSibling );
return theSiblingReturnValue;
}
// -----------------------------------------------------------------
// GetSubModelCount - ask the app how many
//
Int_32
AEObj_pd::GetSubModelCount(DescType inModelKind)
{
// create the aegizmo string that represents the kind we want to count
ostringstream theStream( ios::in | ios::out );
theStream << "'----':" << GetObjAddr();
theStream << ", kocl:type(" << As4CharString(inModelKind) << ")";
// use gizmos to create the apple event
OSErr theErr;
StAEDescriptor theAppleEvent;
theErr = AEBuildAppleEvent( kAECoreSuite, kAECountElements,
GetAppAddrType(),
GetAppAddr(),
GetSizeofAppAddr(),
kAutoGenerateReturnID, kAnyTransactionID,
&theAppleEvent.mDesc, theStream.str().c_str() );
dassert( theErr == noErr );
// and off with it
StAEDescriptor theReplyAppleEvent;
theErr = AESend( &theAppleEvent.mDesc, &theReplyAppleEvent.mDesc, kAEWaitReply,
kAENormalPriority, _TimeoutinTicks, nil, nil );
// package up the return value
Int_32 theRetVal = 0;
if( theErr == noErr )
{
StAEDescriptor theResult;
theErr = AEGetParamDesc( theReplyAppleEvent, keyDirectObject, typeLongInteger, &theResult.mDesc );
if( theErr == noErr )
{
theRetVal = AsInt32( theResult.mDesc );
}
}
return theRetVal;
}
// -----------------------------------------------------------------
// UpdatePropertyValues
//
void
AEObj_pd::UpdatePropertyValues( ProgressProc_hi &inProgressProc , DescType inPropertyID )
{
// get the list of properties associated with this class
vector<Prop_da> theProps = (*_AETE).GetProperties( GetKindID() );
// and ask the app for each one
vector<Prop_da>::iterator theIter = theProps.begin();
vector<Prop_da>::iterator theLast = theProps.end();
while( (theIter != theLast) && (inProgressProc.UserCancelled() == false) )
{
Clone_ut<PropertyValue_pd> thePropertyValue = GetPropertyValue( *theIter );
inProgressProc.NewPropertyValue( thePropertyValue );
++theIter;
}
}
// -----------------------------------------------------------------
// GetAETE
//
Clone_ut< AETE_da >
AEObj_pd::GetAETE()
{
return _AETE;
}
// -----------------------------------------------------------------
// GetObjAddr ... as a gizmo string
//
string
AEObj_pd::GetObjAddr( )
{
// start at the top of the stack
vector<ObjectSpec_da>::iterator theIter = _ObjectSpec.end();
if( _ObjectSpec.back()._Kind == typeNull ) return string("'null'()");
theIter--; // and work your way back up to the top (application)
return GetObjAddrR( theIter );
}
// -----------------------------------------------------------------
// GetObjAddrR
//
string
AEObj_pd::GetObjAddrR( vector<ObjectSpec_da>::iterator &ioIter )
{
string theRetVal;
// recurse to build a gizmo string - see the gizmo docs for the details
if( ioIter->_Kind == cFinderProcess )
{
theRetVal = string("'null'()");
}
else
{
ostringstream theStream;
theStream << "obj {form:indx,want:type('" << As4CharString( ioIter->_Kind ) + "')" +
",seld:" << ioIter->_Pos <<
",from:";
--ioIter;
theStream << GetObjAddrR( ioIter ) + "}";
theRetVal = theStream.str();
}
return theRetVal;
}
// -----------------------------------------------------------------
// GetAppAddr
//
void *
AEObj_pd::GetAppAddr()
{
return &_AppSignature;
}
// -----------------------------------------------------------------
// GetAppAddrType
//
OSType
AEObj_pd::GetAppAddrType()
{
return typeApplSignature;
}
// -----------------------------------------------------------------
// GetSizeofAppAddr
//
Int_32
AEObj_pd::GetSizeofAppAddr()
{
return sizeof(OSType);
}
// -----------------------------------------------------------------
// PushObjSpec ... you never know when your going to change a container
//
void
AEObj_pd::PushObjSpec( ObjectSpec_da &inObjSpec )
{
_ObjectSpec.push_back( inObjSpec );
}
// -----------------------------------------------------------------
// IsValidAETE
//
Boolean
AEObj_pd::IsValidAETE()
{
return !(_AETE.Isnil() );
}
// -----------------------------------------------------------------
// GetFullName ... this is the formal name (e.g. Document #1) and any real name (e.g. "xyz") concatenated
//
string
AEObj_pd::GetFullName()
{
vector<ObjectSpec_da>::iterator theIter = _ObjectSpec.end();
vector<ObjectSpec_da>::iterator theFirst = _ObjectSpec.begin();
string theRetVal;
do {
theIter--;
theRetVal += theIter->_FormalName;
if( theIter->_Name.length() != 0 )
{
theRetVal += string(" (") + theIter->_Name + string(")");
}
// only place the 'of' if it makes sense
if( theIter != theFirst )
{
theRetVal = theRetVal + " of ";
}
} while( theFirst != theIter );
return theRetVal;
}